﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using StockTrader.API.TradingAlgos;
using StockTrader.Broker.IciciDirect;
using StockTrader.Core;
using StockTrader.Platform.Logging;
using StockTrader.Stocks.Utilities.Broker;
using StockTrader.Utilities;
using StockTrader.Utilities.Broker;
using System.Diagnostics;
using System.IO;

namespace StockTrader.UI.Trader
{
    public partial class LiveTrader : Form
    {
        public LiveTrader()
        {
            InitializeComponent();

            InitializePanels();

            this.loginIdTb.Text = "";
            this.passwordTb.Text = "";
            this.panTb.Text = "";
            this.activityPanel.Visible = true;

            // loginSubmit_Click(null, null);
        }
        private void Login_Load(object sender, EventArgs e)
        {
            new Thread(() =>
            {
                Start();
            }).Start();
        }

        private void Start()
        {
            loginSubmit_Click(null, null);
        }

        string _iciciLoginId = "";

        IciciDirectBroker _iciciDirectAccount;
        List<BrokingAccountThread> _brokerThreads = new List<BrokingAccountThread>();
        List<GenericLifeThread> _generalThreads = new List<GenericLifeThread>();
        List<SymbolAlgosThread> _stockThreads = new List<SymbolAlgosThread>();
        BrokingAccountThread _iciciLoginThread = new BrokingAccountThread();
        object _logSyncRoot = new object();
        static object _remoteMsgSyncRoot = new object();
        Dictionary<string, TradingAlgo> _algoSet = new Dictionary<string, TradingAlgo>(10);
        DateTime _lastTimeGetStateCalled = DateTime.Now.AddMinutes(-8);
        bool _startLoginThread = false;

        // Core method
        private TradingAlgo GetAlgo(Instrument instrument, double perc, short algoId = 1, bool isMock = true)
        {
            // Set Algo Params
            AlgoParams algoParams = new AlgoParams();
            algoParams.R1 = "2012";
            algoParams.R2 = "IEOD-live";
            algoParams.IsMock = isMock;
            algoParams.IsReplayMode = false;
            algoParams.ReplayTickFile = "";
            algoParams.AlgoId = algoId;
            algoParams.UseProbableTradeValue = false;
            algoParams.IsMarketClosingSquareOff = true;
            //Params.isSquareOffTrigger = false;
            //Params.isMinProfitMust = false;
            algoParams.PercMarketDirectionChange = perc;
            //Params.percSquareOffThreshold = 0;
            //Params.percStoploss = 0;
            //Params.percMinProfit = 0;
            //Params.allowShort = true;
            //Params.allowLong = true;
            //Params.startOrders = null;
            algoParams.Broker = _iciciDirectAccount;
            algoParams.I = instrument;
            algoParams.MaxTotalPositions = 1;
            algoParams.MaxLongPositions = 1;
            algoParams.MaxShortPositions = 1;
            algoParams.LongCeilingPrice = 100000;
            algoParams.ShortFloorPrice = 0.01;
            algoParams.PercPositionSpacing = 0.01;
            algoParams.PercBrokerage = 0.05;
            algoParams.MarginFraction = 0.25;
            algoParams.SquareOffBrokerageFactor = 1.4;
            algoParams.AlgoIntervalInSeconds = 10;

            if (!isMock)
            {
                algoParams.IsLimitLossPerDay = true;
                algoParams.PercLossStopForDay = 2.5;
                algoParams.NumNettLossTradesStopForDay = 8;
            }

            TradingAlgo algo = AlgoRunUtils.GetAlgo(algoId, algoParams, false);

            algoParams.PositionsFile = SystemUtils.GetAlgoPositionsFileName(algoParams.Description());
            algoParams.StateFile = SystemUtils.GetAlgoStateFileName(algoParams.Description());

            var algoDesc = algoParams.I.Symbol;// +algoParams.AlgoId;// algo.Description();
            algoDesc = algoDesc.ToUpper();
            if (!algoParams.IsMock && !_algoSet.ContainsKey(algoDesc))
                _algoSet.Add(algoDesc, algo);

            return algo;
        }

        private void loginSubmit_Click(object sender, EventArgs e)
        {
            FileTracing.SetTraceDelegate(AppendLog);

            FileTracing.TraceOut("Started Live Trader");
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            // Create ICICI broker account
            _iciciDirectAccount = new IciciDirectBroker(this.loginIdTb.Text, this.passwordTb.Text, this.panTb.Text);

            bool IsMarketOpen = true;
            int retryCnt = 0;
            do
            {
                IsMarketOpen = MarketUtils.IsMarketOpenIncludingPreOpen();
                FileTracing.TraceOut("IsMarketOpen = " + IsMarketOpen);

                if (IsMarketOpen) break;
                else Thread.Sleep(1000 * 30);

            } while (!IsMarketOpen && retryCnt++ < 3);

            if (IsMarketOpen)// && (errorCode = TryLoggingIn()) == BrokerErrorCode.Success)
            {
                SetPanelsOnLogin();

                SetWelcomeText("Welcome " + _iciciLoginId + " !");

                if (_startLoginThread)
                    // Thread 1
                    StartLoginCheckerThread();

                PlaceAdhocOrders();

                var obj = new GenericLifeThread { thread = new Thread(new ParameterizedThreadStart(CheckMarketClosing)) };
                obj.thread.Name = "\"" + _iciciLoginId + "\":" + " CheckMarketClosing";
                obj.thread.Start(obj);
                //_generalThreads.Add(obj);

                //obj = new GenericLifeThread { thread = new Thread(new ParameterizedThreadStart(CheckRemoteCommand)) };
                //obj.thread.Name = "\"" + _iciciLoginId + "\":" + " CheckRemoteCommand";
                //obj.thread.Start(obj);
                //_generalThreads.Add(obj);

                obj = new GenericLifeThread { thread = new Thread(new ParameterizedThreadStart(CheckNetwork)) };
                obj.thread.Name = "\"" + _iciciLoginId + "\":" + " CheckNetwork";
                obj.thread.Start(obj);
                _generalThreads.Add(obj);

                obj = new GenericLifeThread { thread = new Thread(new ParameterizedThreadStart(SendAlgoState)) };
                obj.thread.Name = "\"" + _iciciLoginId + "\":" + " SendAlgoState";
                obj.thread.Start(obj);
                _generalThreads.Add(obj);


                // Start Algos
                double perc = 1.00;
                InstrumentType instrType = InstrumentType.FutureStock;
                Instrument instr = null;
                int i = 1;
                List<ITradingAlgo> algos = new List<ITradingAlgo>();
                DateTime date = new DateTime(2013, 03, 28);
                int algoId = 2;

                algos.Clear();
                instr = new Instrument("NIFTY", InstrumentType.FutureIndex, date, 50);
                //algos.Add(GetAlgo(instr, 0.4, 42, false));//110,100 , 0.4
                StartAlgoThread(instr, algos, 10000); Thread.Sleep(1000 * i++);

                algos.Clear();
                instr = new Instrument("TELCO", InstrumentType.FutureStock, date, 1000);
                //algos.Add(GetAlgo(instr, 0.1, 13, false)); //13, 18, 14, 0.1
                StartAlgoThread(instr, algos, 10000); Thread.Sleep(1000 * i++);

                // *** risky
                algos.Clear();
                instr = new Instrument("YESBAN", InstrumentType.FutureStock, date, 1000);// *** risky
                //algos.Add(GetAlgo(instr, 0.4, 18, false));
                StartAlgoThread(instr, algos, 10000); Thread.Sleep(1000 * i++);

                algos.Clear();
                instr = new Instrument("STABAN", InstrumentType.FutureStock, date, 125);
                //algos.Add(GetAlgo(instr, 0.6, 32, false));  //0.6,42
                StartAlgoThread(instr, algos, 10000); Thread.Sleep(1000 * i++);

                algos.Clear();
                instr = new Instrument("INFTEC", InstrumentType.FutureStock, date, 125);
                //algos.Add(GetAlgo(instr, 0.4, 41, false)); //0.2, 31, 114, 0.3
                StartAlgoThread(instr, algos, 10000); Thread.Sleep(1000 * i++);

                algos.Clear();
                //instr = new Instrument("JAIASS", InstrumentType.FutureStock, date, 4000);
                //algos.Add(GetAlgo(instr, 0.2, 18, false)); //18, 0.6,0.10
                //StartAlgoThread(instr, algos, 10000); Thread.Sleep(1000 * i++);

                algos.Clear();
                instr = new Instrument("BHATE", InstrumentType.FutureStock, date, 1000);
                //algos.Add(GetAlgo(instr, 0.3, 40, false));
                StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

                algos.Clear();
                instr = new Instrument("CNXBAN", InstrumentType.FutureIndex, date, 25);
                //algos.Add(GetAlgo(instr, 0.5, 18, false));
                StartAlgoThread(instr, algos, 10000); Thread.Sleep(1000 * i++);

                algos.Clear();
                instr = new Instrument("BAAUTO", InstrumentType.FutureIndex, date, 125);
                //algos.Add(GetAlgo(instr, 0.2, 50, false));
                StartAlgoThread(instr, algos, 20000); Thread.Sleep(1000 * i++);

                StartTickCollectionMockAlgos();

                // Send starter mail
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("------ Stocks ON ------");
                foreach (var algodesc in _algoSet.Keys)
                    sb.AppendLine(algodesc);
                var algosStarted = sb.ToString();
                sb.AppendLine("------ Commands ------");
                var values = Enum.GetNames(typeof(RemoteCommand));
                sb.AppendLine(string.Join("\n", values));
                sb.AppendLine("Individual commands eg. symbol1:cmd1;symbol2:cmd2...");
                MessagingUtils.SendAlertMessage("Started", sb.ToString(), algosStarted);
            }
            else
            {
                FileTracing.TraceOut("Exiting since market is closed!");
                Application.Exit();
            }
        }

        private void StartTickCollectionMockAlgos()
        {
            // Start Algos
            double perc = 1.00;
            InstrumentType instrType = InstrumentType.FutureStock;
            Instrument instr = null;
            int i = 1;
            List<ITradingAlgo> algos = new List<ITradingAlgo>();
            DateTime date = new DateTime(2013, 03, 28);
            int algoId = 2;

            //algos.Clear();
            //instr = new Instrument("MINIFT", InstrumentType.FutureIndex, date, 20);
            //algos.Add(GetAlgo(instr, 0.4, 119, false)); // 0.3, 61
            //StartAlgoThread(instr, algos, 10000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("DLFLIM", InstrumentType.FutureIndex, date, 1000);
            //algos.Add(GetAlgo(instr, 0.4, 44, false)); // 0.4, 50
            //StartAlgoThread(instr, algos, 10000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("MCDOWE", InstrumentType.FutureStock, date, 250);
            ////algos.Add(GetAlgo(instr, 0.6, 42, false));
            //StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("SAIL", InstrumentType.FutureStock, date, 2000);
            ////algos.Add(GetAlgo(instr, 0.5, 40, false));
            ////StartAlgoThread(instr, algos, 25000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("RELIND", InstrumentType.FutureStock, date, 250);
            ////StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("WIPRO", InstrumentType.FutureStock, date, 500);
            //StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("COALIN", InstrumentType.FutureStock, date, 1000);
            //StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("CAIIND", InstrumentType.FutureStock, date, 1000);
            //StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("HINDAL", InstrumentType.FutureStock, date, 2000);
            //StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("BATIND", InstrumentType.FutureStock, date, 500);
            //StartAlgoThread(instr, algos, 25000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("BHEL", InstrumentType.FutureStock, date, 1000);
            //StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("ADAPOW", InstrumentType.FutureStock, date, 4000);
            //StartAlgoThread(instr, algos, 25000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("ICIBAN", InstrumentType.FutureStock, date, 250);
            //StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);


            // -------------------------------- OPTIONS -------------------------------------------------
            // NIFTY CALLs
           
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionCallIndex, 6000, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionCallIndex, 6100, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionCallIndex, 6200, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionCallIndex, 5700, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionCallIndex, 5800, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionCallIndex, 5900, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

            // NIFTY PUTs
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionPutIndex, 5800, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionPutIndex, 6000, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionPutIndex, 6100, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionPutIndex, 5600, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionPutIndex, 5700, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("NIFTY", InstrumentType.OptionPutIndex, 5900, new DateTime(2013, 03, 28), 50);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);

            // CNXBAN CALLs
            algos.Clear();
            instr = new Instrument("CNXBAN", InstrumentType.OptionCallIndex, 12300, new DateTime(2013, 03, 28), 25);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("CNXBAN", InstrumentType.OptionCallIndex, 11900, new DateTime(2013, 03, 28), 25);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("CNXBAN", InstrumentType.OptionCallIndex, 12100, new DateTime(2013, 03, 28), 25);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();


            // CNXBAN PUTSs
            algos.Clear();
            instr = new Instrument("CNXBAN", InstrumentType.OptionPutIndex, 12000, new DateTime(2013, 03, 28), 25);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("CNXBAN", InstrumentType.OptionPutIndex, 11800, new DateTime(2013, 03, 28), 25);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();
            instr = new Instrument("CNXBAN", InstrumentType.OptionPutIndex, 12200, new DateTime(2013, 03, 28), 25);
            StartAlgoThread(instr, algos, 15000); Thread.Sleep(1000 * i++);
            algos.Clear();

            //algos.Clear();
            //instr = new Instrument("STABAN", InstrumentType.OptionCallStock, 2050, new DateTime(2013, 03, 28), 125);
            //StartAlgoThread(instr, algos, 25000); Thread.Sleep(1000 * i++);

            //algos.Clear();
            //instr = new Instrument("STABAN", InstrumentType.OptionPutStock, 2100, new DateTime(2013, 03, 28), 125);
            //StartAlgoThread(instr, algos, 25000); Thread.Sleep(1000 * i++);

        }

        private void PlaceAdhocOrders()
        {
            return;
            string orderRef = "";
            BrokerErrorCode code =
                _iciciDirectAccount.PlaceDerivativeOrder("INFTEC", 125, 61.5,
                  OrderPriceType.LIMIT, OrderDirection.SELL,
                  InstrumentType.OptionCallStock,
                  2500,
                  MarketUtils.GetExpiryExactDate(new DateTime(2013, 03, 28)),
                  OrderGoodNessType.GTD,
                  out orderRef);

            FileTracing.TraceOut("Placed order1: " + code + " : " + orderRef);

            code =
                _iciciDirectAccount.PlaceDerivativeOrder("INFTEC", 125, 47.5,
                  OrderPriceType.LIMIT, OrderDirection.SELL,
                  InstrumentType.OptionCallStock,
                  2500,
                  MarketUtils.GetExpiryExactDate(new DateTime(2013, 03, 28)),
                  OrderGoodNessType.GTD,
                  out orderRef);

            FileTracing.TraceOut("Placed order2: " + code + " : " + orderRef);
        }

        private void StartAlgoThread(Instrument instrument, List<ITradingAlgo> algos, int tickIntervalInMiliSecs = 10000)
        {
            List<ITradingAlgo> algosCopy = new List<ITradingAlgo>(algos);
            object tickGenerator = null;
            if (instrument.InstrumentType == InstrumentType.Share)
                tickGenerator = new EquitySymbolLiveTickGenerator(_iciciDirectAccount, instrument);
            else
                tickGenerator = new DerivativeSymbolLiveTickGenerator(_iciciDirectAccount, instrument);

            BrokerSymbolAlgosObject brokerSymbolAlgosObj = new BrokerSymbolAlgosObject(_iciciDirectAccount, instrument, algosCopy, tickGenerator, tickIntervalInMiliSecs);
            Thread thread = new Thread(new ParameterizedThreadStart(AlgoRunner.BG_StockWorkerThread_SingleSymbol));

            SymbolAlgosThread symbolAlgosThread = new SymbolAlgosThread();

            symbolAlgosThread.BrokerSymbolAlgosObj = brokerSymbolAlgosObj;
            symbolAlgosThread.thread = thread;

            _stockThreads.Add(symbolAlgosThread);

            symbolAlgosThread.thread.Name = "\"" + _iciciLoginId + "\": " + instrument.ToString();
            symbolAlgosThread.thread.IsBackground = true;

            symbolAlgosThread.thread.Start(brokerSymbolAlgosObj);
        }

        private void StartLoginCheckerThread()
        {
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            errorCode = _iciciDirectAccount.CheckAndLogInIfNeeded(false);

            // If login password is invalid then immediately exit the program 
            // to avoid locking of account by retrying with bad login/password
            if (errorCode == BrokerErrorCode.InvalidLoginPassword || errorCode == BrokerErrorCode.ChangePassword)
            {
                FileTracing.TraceOut("InvalidLoginPassword");
                return;
            }
            if (errorCode != BrokerErrorCode.Success)
            {
                throw new Exception("CheckAndLogInIfNeeded(). BrokerErrorCode=" + errorCode.ToString());
            }

            // Separate Login thread in background
            Thread thread = new Thread(new ParameterizedThreadStart(LoginUtils.Background_LoginCheckerThread));
            BrokingAccountObject iciciAccObj = new BrokingAccountObject(_iciciDirectAccount);
            _iciciLoginThread.brokerAccountObj = iciciAccObj;
            _iciciLoginThread.thread = thread;

            //_brokerThreads.Add(_iciciLoginThread);

            _iciciLoginThread.thread.Name = "Main Login Thread of \"" + _iciciLoginId + "\"";
            _iciciLoginThread.thread.IsBackground = true;

            _iciciLoginThread.thread.Start(iciciAccObj);

            //_loginThStarted = true;
        }
        private void CheckMarketClosing(object obj)
        {
            bool mktClosingMsgSent = false;
            var thObj = (GenericLifeThread)obj;
            Thread.Sleep(1000 * 60 * 1);
            while (!thObj.bStopThread)
            {
                bool IsMarketOpen = MarketUtils.IsMarketOpenIncludingPreOpen();

                if (!mktClosingMsgSent)
                {
                    bool IsMarketClosingWindow = MarketUtils.IsTimeAfter320();

                    if (IsMarketClosingWindow)
                    {
                        var desc = StockUtils.CollateAlgoStates(_algoSet.Values);
                        MessagingUtils.SendAlertMessage("ST-State", desc);
                        _lastTimeGetStateCalled = DateTime.Now;
                        mktClosingMsgSent = true;
                    }
                }

                if (!IsMarketOpen)
                    break;

                else
                    Thread.Sleep(1000 * 60 * 2);
            }
            ExitForTheDay();
        }
        private void ExitForTheDay()
        {
            logoutBtn_Click(null, null);

            var msg = "Logged out and exiting for the day. ";
            var desc = StockUtils.CollateAlgoStates(_algoSet.Values);
            desc = msg + desc;
            MessagingUtils.SendAlertMessage("Logout", desc, desc);
            FileTracing.TraceOut(desc);

            Thread.Sleep(1000 * 10);

            Environment.Exit(0);

            ProcessStartInfo start = new ProcessStartInfo();
            string exeLocation = Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "HibernateSystem.exe");
            // Enter the executable to run, including the complete path 
            start.FileName = exeLocation;

            // Do you want to show a console window? 
            start.WindowStyle = ProcessWindowStyle.Normal;// Hidden;
            start.CreateNoWindow = false;// true;

            using (Process proc = Process.Start(start))
            {

            }
            Environment.Exit(0);
            // Hibernate system
            bool retVal = Application.SetSuspendState(PowerState.Hibernate, true, false);
        }
        private void CheckRemoteCommand(object obj)
        {
            MessagingUtils.Init(RemoteMessageReceived, RemoteMessageReceived, "@gmail.com");
            var thObj = (GenericLifeThread)obj;
            Thread.Sleep(1000 * 60 * 1);
            while (!thObj.bStopThread)
            {
                FileTracing.TraceOut("Periodic remote command check via email");
                MessagingUtils.ReadMailMessages();
                GC.Collect();
                Thread.Sleep(1000 * 60 * 2);
            }
        }
        private void CheckNetwork(object obj)
        {
            var thObj = (GenericLifeThread)obj;
            bool isSuspended = false;
            Thread.Sleep(1000 * 60 * 1);
            while (!thObj.bStopThread)
            {
                try
                {
                    FileTracing.TraceOut("Periodic network check");
                    var isNetworkAvailable = false;
                    try
                    {
                        //var data = HttpHelper.GetWebPageResponse("http://google.com", null, null, new System.Net.CookieContainer());
                        int retries = 0;
                        do
                        {
                            isNetworkAvailable = RemoteUtils.IsNetworkAvailable();// && RemoteUtils.CheckPingResponse();

                            if (!isNetworkAvailable)
                                Thread.Sleep(1000 * 5);

                        } while (!isNetworkAvailable && ++retries <= 3);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogException(ex);
                    }

                    if (!isNetworkAvailable)
                    {
                        var msg = "Network not available...Suspending threads temporarily";
                        MessagingUtils.SendAlertMessage("NetworkDown", msg, msg);
                        FileTracing.TraceOut(msg);
                        // Pause the threads
                        isSuspended = true;
                        if (_iciciLoginThread.thread != null && _iciciLoginThread.thread.IsAlive)
                            _iciciLoginThread.thread.Suspend();
                        foreach (var th in _stockThreads)
                            th.thread.Suspend();
                    }
                    else if (isNetworkAvailable && isSuspended)
                    {
                        var msg = "Network now available...Resuming threads";
                        MessagingUtils.SendAlertMessage("NetworkUp", msg, msg);
                        FileTracing.TraceOut(msg);
                        // Resume the threads
                        if (_iciciLoginThread.thread != null && _iciciLoginThread.thread.IsAlive)
                            _iciciLoginThread.thread.Resume();
                        foreach (var th in _stockThreads)
                            th.thread.Resume();

                        isSuspended = false;
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogException(ex);
                }

                Thread.Sleep(1000 * 60 * 1);
            }
        }
        private void SendAlgoState(object obj)
        {
            var thObj = (GenericLifeThread)obj;
            Thread.Sleep(1000 * 60 * 1);
            while (!thObj.bStopThread)
            {
                var timeLapsed = DateTime.Now - _lastTimeGetStateCalled;
                if (timeLapsed >= new TimeSpan(0, 10, 0))
                {
                    if (StockUtils.IsAnyOpenPosition(_algoSet.Values))
                    {
                        var desc = StockUtils.CollateAlgoStates(_algoSet.Values);
                        MessagingUtils.SendAlertMessage("ST-State", desc);
                    }
                    _lastTimeGetStateCalled = DateTime.Now;
                }
                Thread.Sleep(Math.Min(1000 * 60 * 10, Math.Min((int)timeLapsed.TotalMilliseconds, int.MaxValue)));
            }
        }
        public void RemoteMessageReceived(string msgText)
        {
            try
            {
                lock (_remoteMsgSyncRoot)
                {
                    FileTracing.TraceOut("Remote Message received: " + msgText);

                    if (msgText.ToUpper() == "SOSEXIT" || msgText.ToUpper() == "EXITALL")
                    {
                        MessagingUtils.SendAlertMessage("Exit", "Exited all algos and Trader exit");
                        ExitForTheDay();
                        return;
                    }

                    if (msgText.ToUpper().Contains("PAUSENEWPOSALL"))
                    {
                        ExecuteAlgoCmds(4, "PAUSENEWPOSALL", _algoSet.Values, false);
                        MessagingUtils.SendAlertMessage("Pause", "Paused new pos for all algos");
                        return;
                    }

                    if (msgText.ToUpper().Contains("SQUAREOFFATPROFITRESETALL"))
                    {
                        ExecuteAlgoCmds(7, "SQUAREOFFATPROFITRESETALL", _algoSet.Values, true);
                        //MessagingUtils.SendAlertMessage("Pause", "Paused all algos");
                        return;
                    }

                    if (msgText.ToUpper().Contains("SQUAREOFFATPROFITPAUSEALL"))
                    {
                        ExecuteAlgoCmds(6, "SQUAREOFFATPROFITPAUSEALL", _algoSet.Values, true);
                        //MessagingUtils.SendAlertMessage("Pause", "Paused all algos");
                        return;
                    }

                    if (msgText.ToUpper().Contains("SQUAREOFFATPROFITALL"))
                    {
                        ExecuteAlgoCmds(5, "SQUAREOFFATPROFITALL", _algoSet.Values, true);
                        //MessagingUtils.SendAlertMessage("Pause", "Paused all algos");
                        return;
                    }

                    if (msgText.ToUpper().Contains("SQUAREOFFALL"))
                    {
                        ExecuteAlgoCmds(3, "SQUAREOFFALL", _algoSet.Values, true);
                        //MessagingUtils.SendAlertMessage("Pause", "Paused all algos");
                        return;
                    }

                    if (msgText.ToUpper().Contains("SQUAREOFFPAUSEALL"))
                    {
                        ExecuteAlgoCmds(3, "SQUAREOFFPAUSEALL", _algoSet.Values, true);
                        //MessagingUtils.SendAlertMessage("Pause", "Paused all algos");
                        return;
                    }

                    if (msgText.ToUpper().Contains("RESETFULLALL"))
                    {
                        ExecuteAlgoCmds(3, "RESETFULL", _algoSet.Values, false);
                        MessagingUtils.SendAlertMessage("Reset", "ResetFull all algos");
                        return;
                    }
                    if (msgText.ToUpper().Contains("RESETCOREALL"))
                    {
                        ExecuteAlgoCmds(3, "RESETCORE", _algoSet.Values, false);
                        MessagingUtils.SendAlertMessage("Reset", "ResetCore all algos");
                        return;
                    }
                    if (msgText.ToUpper().Contains("RESETDIRALL"))
                    {
                        ExecuteAlgoCmds(3, "RESETDIR", _algoSet.Values, false);
                        MessagingUtils.SendAlertMessage("Reset", "ResetDir all algos");
                        return;
                    }
                    if (msgText.ToUpper().Contains("RESETPOSALL"))
                    {
                        ExecuteAlgoCmds(3, "RESETPOS", _algoSet.Values, false);
                        MessagingUtils.SendAlertMessage("Reset", "ResetPos all algos");
                        return;
                    }

                    if (msgText.ToUpper().Contains("GETSTATEALL"))
                    {
                        var desc = StockUtils.CollateAlgoStates(_algoSet.Values);
                        MessagingUtils.SendAlertMessage("GetState", desc);
                        _lastTimeGetStateCalled = DateTime.Now;
                        return;
                    }

                    if (msgText.ToUpper().Contains("STOPALL"))
                    {
                        ExecuteAlgoCmds(0, "STOPALL", _algoSet.Values, false);
                        MessagingUtils.SendAlertMessage("Stop", "Stopped all algos");
                        return;
                    }

                    if (msgText.ToUpper().Contains("PAUSEALL"))
                    {
                        ExecuteAlgoCmds(1, "PAUSEALL", _algoSet.Values, false);
                        MessagingUtils.SendAlertMessage("Pause", "Paused all algos");
                        return;
                    }

                    if (msgText.ToUpper().Contains("RESUMEALL"))
                    {
                        ExecuteAlgoCmds(2, "RESUMEALL", _algoSet.Values, false);
                        MessagingUtils.SendAlertMessage("Resume", "Resumed all algos");
                        return;
                    }



                    var algoCmds = msgText.Split(';');
                    foreach (var algoCmd in algoCmds)
                    {
                        var pair = algoCmd.Contains(":") ? algoCmd.Split(':') : algoCmd.Split(' ');
                        var algoName = pair[0].Trim().ToUpper();
                        var cmd = pair[1].Trim().ToUpper();
                        if (_algoSet.ContainsKey(algoName))
                        {
                            int cmdType = -1;
                            if (cmd == "STOP")
                                cmdType = 0;
                            else if (cmd == "PAUSE")
                                cmdType = 1;
                            else if (cmd == "RESUME")
                                cmdType = 2;
                            else if (cmd.Contains("RESET"))
                                cmdType = 3;
                            else if (cmd == "PAUSENEWPOS")
                                cmdType = 4;
                            else if (cmd == "SQUAREOFFATPROFIT")
                                cmdType = 5;
                            else if (cmd == "SQUAREOFFATPROFITPAUSE")
                                cmdType = 6;
                            else if (cmd == "SQUAREOFFPAUSE")
                                cmdType = 3;
                            else if (cmd == "SQUAREOFF")
                                cmdType = 3;

                            ExecuteAlgoCmds(cmdType, cmd, new TradingAlgo[] { _algoSet[algoName] });
                        }
                    }

                    return;

                    // Do it later
                    Dictionary<string, Dictionary<string, string>> algoCmdSet = new Dictionary<string, Dictionary<string, string>>();
                    foreach (var algoCmd in algoCmds)
                    {
                        var cmds = algoCmd.Split(':');
                        var cmdPairs = new Dictionary<string, string>();
                        foreach (var c in cmds)
                        {
                            var pair = c.Split('=');
                            var ck = pair[0].ToUpper();
                            var cv = pair[1].ToUpper();

                            if (ck == "N")
                            {
                                if (!algoCmdSet.ContainsKey(cv))
                                    algoCmdSet.Add(cv, cmdPairs);
                            }
                            else cmdPairs.Add(ck, cv);
                        }
                    }

                    // First stop the algos
                    foreach (var akv in algoCmdSet)
                    {
                        if (_algoSet.ContainsKey(akv.Key))
                            _algoSet[akv.Key].DoStopAlgo = true;
                    }

                    Thread.Sleep(1000 * 5);

                    // Now execute cmds
                    foreach (var akv in algoCmdSet)
                    {
                        if (_algoSet.ContainsKey(akv.Key))
                        {
                            TradingAlgo algo = _algoSet[akv.Key];

                            if (algo.AlgoWorkingState != AlgoOrderPlaceState.RUNNING)
                            {

                            }


                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
            }
        }

        private void ExecuteAlgoCmds(int cmdType, string cmdCode, ICollection<TradingAlgo> algos, bool doAlert = true)
        {
            // Stop
            if (cmdType == 0)
            {
                foreach (var algo in algos)
                    algo.Stop(doAlert);
            }

            // Pause
            if (cmdType == 1)
            {
                foreach (var algo in algos)
                    algo.Pause(doAlert);
            }

            // Resume
            if (cmdType == 2)
            {
                foreach (var algo in algos)
                    algo.Resume(doAlert);
            }

            // PauseNewPos
            if (cmdType == 4)
            {
                foreach (var algo in algos)
                    algo.PauseNewPos(doAlert);
            }

            // SquareOffAtProfit
            if (cmdType == 5)
            {
                foreach (var algo in algos)
                    algo.SquareOffAtProfit(doAlert);
            }

            // SquareOffAtProfitPause
            if (cmdType == 6)
            {
                foreach (var algo in algos)
                    algo.SquareOffAtProfitPause(doAlert);
            }

            // SquareOffAtProfitReset
            if (cmdType == 7)
            {
                foreach (var algo in algos)
                    algo.SquareOffAtProfitReset(doAlert);
            }

            if (cmdType != 3) // 3 is long running or to be done in sync type commands
                return;

            // Heavy commands
            // Pause temporarily
            foreach (var algo in algos)
                algo.DoStopAlgo = true;

            foreach (var algo in algos)
            {
                // Execute command after algo is in not running state
                while (!algo.IsExternallySuspended)
                    Thread.Sleep(1000);

                switch (cmdCode)
                {
                    case "RESETFULL":
                        algo.ResetFull(doAlert);
                        break;

                    case "RESETCORE":
                        algo.ResetCore(doAlert);
                        break;

                    case "RESETDIR":
                        algo.ResetDir(doAlert);
                        break;

                    case "RESETPOS":
                        algo.ResetPos(doAlert);
                        break;

                    case "SQUAREOFF":
                        algo.SquareOff(doAlert);
                        break;

                    case "SQUAREOFFPAUSE":
                        algo.SquareOffPause(doAlert);
                        break;
                }
            }

            // Resume back
            foreach (var algo in algos)
                algo.DoStopAlgo = false;

        }

        private BrokerErrorCode TryLoggingIn()
        {
            _iciciLoginId = this.loginIdTb.Text;


            // LOGIN 
            BrokerErrorCode errorCode = BrokerErrorCode.Success;
            errorCode = _iciciDirectAccount.CheckAndLogInIfNeeded(true, false);
            // If login password is invalid then immediately exit the program 
            // to avoid locking of account by retrying with bad login/password

            string message = "";

            switch (errorCode)
            {
                case BrokerErrorCode.ChangePassword:
                    message = "You need to change password. Goto website and change before logging in here.";
                    break;

                case BrokerErrorCode.InvalidLoginPassword:
                    message = "Invalid LoginIdPassword. Please try, but not more than 2 times to avoid locking the account.";
                    break;

                case BrokerErrorCode.Success:
                    message = "Login Successful";
                    break;

                default:
                    message = errorCode.ToString();
                    break;
            }

            FileTracing.TraceOut("Login for " + this.loginIdTb.Text + "." + message);

            AppendLog(message);

            return errorCode;
        }

        private void logoutBtn_Click(object sender, EventArgs e)
        {
            EndStockThreads();

            _iciciDirectAccount.LogOut();

            SetPanelsOnLogout();

            string logOutMessage = _iciciLoginId + " has been successfully logged out";

            AppendLog(logOutMessage);
        }
        private void EndStockThreads()
        {
            foreach (SymbolAlgosThread stockThread in _stockThreads)
            {
                // signal the stock threads to stop and wait for them to complete
                stockThread.BrokerSymbolAlgosObj.DoStopThread = true;
            }

            foreach (SymbolAlgosThread stockThread in _stockThreads)
            {
                stockThread.thread.Join();
            }
            _stockThreads.Clear();

            for (int i = 0; i < _generalThreads.Count; i++)
            {
                // signal the generic threads to stop and wait for them to complete
                _generalThreads[i].bStopThread = true;
                _generalThreads[i].thread.Join();
            }

            _generalThreads.Clear();

            if (_iciciLoginThread.thread != null && _iciciLoginThread.thread.IsAlive)
            {
                _iciciLoginThread.brokerAccountObj.DoStopThread = true;
                _iciciLoginThread.thread.Join();
            }
        }
    }
}
